package br.com.ps.bombertournament.game;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;

/**
 * Contains all objects must be rendered on the scene
 * 
 * @author Rennan Stefan Boni - rennanboni@gmail.com
 */
public class Layer implements GameObject {

	private int priority;

	private List<BaseGameObject> queueRender;
	private List<BaseGameObject> addQueueRender;
	private List<BaseGameObject> removeQueueRender;
	private Renderer renderer;

	private Comparator<BaseGameObject> comparator = new Perpective2D();

	public Layer(Renderer game, int initialCapacity, int priority) {
		queueRender = new ArrayList<BaseGameObject>(initialCapacity);
		addQueueRender = new ArrayList<BaseGameObject>(initialCapacity);
		removeQueueRender = new ArrayList<BaseGameObject>(initialCapacity);
		this.renderer = game;

		this.priority = priority;
	}

	public Layer(Renderer game, int initialCapacity) {
		queueRender = new ArrayList<BaseGameObject>(initialCapacity);
		addQueueRender = new ArrayList<BaseGameObject>(initialCapacity);
		removeQueueRender = new ArrayList<BaseGameObject>(initialCapacity);
		this.renderer = game;
	}

	public Layer(Renderer game) {
		this(game, 10);
	}

	/**
	 * Render all objects in the list
	 * 
	 * @param spriteBatch
	 *            Local where will be rendered the game objects
	 */
	public void render(SpriteBatch spriteBatch) {
		if (queueRender != null) {
			for (BaseGameObject renderable : queueRender) {
				renderable.render(spriteBatch);
			}
		}
	}

	/**
	 * Add new game object on the list render
	 * 
	 * @param gameObject
	 *            New game object
	 * @return Return true if the game object was added, otherwise return false
	 */
	public boolean add(BaseGameObject gameObject) {
		boolean result = false;

		if (gameObject != null) {
			result = addQueueRender.add(gameObject);
			gameObject.setLayer(this);
		}

		return result;
	}

	/**
	 * remove the game object on the list render
	 * 
	 * @param gameObject
	 *            The game object will be removed on the list render
	 * @return Return true if the game object was removed, otherwise return
	 *         false
	 */
	public boolean remove(BaseGameObject gameObject) {
		return removeQueueRender.add(gameObject);
	}

	/**
	 * Dispose the layer and all game object on the list render
	 */
	public void dispose() {
		if (queueRender != null) {
			for (BaseGameObject renderable : queueRender) {
				renderable.dispose();
			}
		}
	}

	/**
	 * Update the Layer. <br>
	 * Add/Remove all pending items on the root render list and call the update
	 * method all game object
	 * 
	 * @param deltaTime
	 *            The delta time value
	 */
	public void update(float deltaTime) {
		if (queueRender != null) {

			// Adicionando na lista o objetos pendentes
			addPending();

			// Removendo na lista o objetos pendentes
			removePending();

			for (BaseGameObject renderable : queueRender) {
				renderable.update(Gdx.graphics.getDeltaTime());
			}

			Collections.sort(queueRender, comparator);
		}
	}

	/**
	 * Find the game object with a specific id
	 * 
	 * @param id
	 *            The id value who is looking for
	 * @return Return the game object founded, can return null.
	 */
	public BaseGameObject findObjectById(String id) {
		BaseGameObject result = null;

		if (queueRender != null) {
			for (BaseGameObject renderable : queueRender) {
				result = renderable.getId() != null
						&& id.equals(renderable.getId()) ? renderable : null;

				if (result != null) {
					break;
				}
			}
		}

		return result;
	}

	/**
	 * Add pending game object on the root render list
	 */
	public void addPending() {
		// Adicionando na lista o objetos pendentes
		for (BaseGameObject gameObject : addQueueRender) {
			queueRender.add(gameObject);
		}

		addQueueRender.clear();
	}

	/**
	 * Remove pending game object on the root render list
	 */
	private void removePending() {
		// Removendo na lista o objetos pendentes
		for (BaseGameObject gameObject : removeQueueRender) {
			queueRender.remove(gameObject);
			gameObject.onRemove();
			gameObject.setLayer(null);
		}

		removeQueueRender.clear();
	}

	/**
	 * Return the render list of the layer
	 * 
	 * @return Return a list of game object
	 */
	public List<BaseGameObject> getQueueRender() {
		return queueRender;
	}

	/**
	 * Return the priority of the Layer
	 * 
	 * @return Return the priority of the Layer
	 */
	public int getPriority() {
		return priority;
	}

	public Renderer getRenderer() {
		return renderer;
	}

	public void setGame(Renderer renderer) {
		this.renderer = renderer;
	}

}
